#include "pw_pbl/Coroutine/VectorExecutor.hpp"
#include <algorithm>
#include <cassert>
#include <iterator>
#include <pw_pbl/Coroutine.hpp>
#include <utility>

namespace pw_pbl::co
{
	static consteval VectorExecutor &exec() { return _co::ExecutorFactory<VectorExecutor>::instance(); }

	VectorExecutor::IAwaitable::~IAwaitable() noexcept
	{
		if (!resume_handler)
			return;
		auto pos = std::ranges::find(exec().pending, VectorExecutor::ExecItem{*this});
		if (pos != exec().pending.end())
		{
			exec().pending.erase(pos);
			return;
		}
		pos = std::ranges::find(exec().queue, VectorExecutor::ExecItem{*this});
		if (pos != exec().queue.end())
			exec().queue.erase(pos);
	}

	void VectorExecutor::await_suspend(VectorExecutor::IAwaitable &fr)
	{
		pending.push_back({fr});
	}

	bool VectorExecutor::run(void) &
	{
		std::swap(queue, pending);
		if (queue.empty())
			return true;
		std::ranges::reverse(queue);
		while (!queue.empty())
		{
			auto cur = queue.back();
			queue.pop_back();
			assert(cur.awaitor != nullptr);
			if (cur.awaitor->virtual_ready())
			{
				assert(cur.awaitor->resume_handler);
				std::exchange(cur.awaitor->resume_handler, nullptr).resume();
			}
			else
				pending.push_back(std::move(cur));
		}

		return !pending.empty();
	}
} // namespace pw_pbl::co
